/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.properties; import java.awt.Image; import java.awt.Toolkit; import java.awt.datatransfer.*; import java.beans.*; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.ResourceBundle; import javax.swing.table.*; import javax.swing.event.TableModelEvent; import javax.swing.JTable; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.datatransfer.*; import org.openide.actions.InstantiateAction; import org.openide.util.HelpCtx; import org.openide.util.RequestProcessor; import org.openide.util.NbBundle; import org.openide.util.NbBundle; import org.openide.util.WeakListener; import org.openide.util.actions.SystemAction; import org.openide.nodes.*; import org.openide.loaders.*; import org.openide.*; /** Model for the properties edit table * * @author Petr Jiricka */ public class PropertiesTableModel extends AbstractTableModel { /** generated Serialized Version UID */ // static final long serialVersionUID = -7882925922830244768L; /** Main dataobject */ PropertiesDataObject obj; /** Listens to changes on the underlying dataobject */ private PropertyChangeListener pcl; /** Listens to changes on the bundle structure */ private PropertyBundleListener pbl; static final long serialVersionUID =23879742006423050L; /** Create a data node for a given data object. * The provided children object will be used to hold all child nodes. * @param obj object to work with * @param ch children container for the node */ public PropertiesTableModel (PropertiesDataObject obj) { super (); this.obj = obj; // listener for the DataObject pcl = new PropertyChangeListener () { public void propertyChange(PropertyChangeEvent evt) { // PENDING - should be finer if (evt.getPropertyName().equals(PropertiesDataObject.PROP_FILES)) { fireTableStructureChanged(); } } }; obj.getBundleStructure().addPropertyChangeListener(new WeakListener.PropertyChange(pcl)); // listener for the BundleStructure pbl = new TablePropertyBundleListener(); obj.getBundleStructure().addPropertyBundleListener(new WeakListenerPropertyBundle(pbl)); //PENDING move the column corresponding to curNode to the beginning } class TablePropertyBundleListener implements PropertyBundleListener { public void bundleChanged(PropertyBundleEvent evt) { // PENDING - should be maybe even finer switch (evt.getChangeType()) { // structure changed case PropertyBundleEvent.CHANGE_STRUCT: cancelEditingInTables(getDefaultCancelSelector()); fireTableStructureChanged(); //System.out.println(PropertiesTableModel.this.toString()); break; // all items changed (keyset) case PropertyBundleEvent.CHANGE_ALL: cancelEditingInTables(getDefaultCancelSelector()); fireTableDataChanged(); //System.out.println(PropertiesTableModel.this.toString()); break; // file changed case PropertyBundleEvent.CHANGE_FILE: final int index = obj.getBundleStructure().getEntryIndexByFileName(evt.getEntryName()); if (index == -1) { if (Boolean.getBoolean("netbeans.debug.exceptions")) (new Exception("Changed file not found")).printStackTrace(); break; } cancelEditingInTables(new CancelSelector() { public boolean doCancelEditing(int row, int column) { if (!(row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount())) return false; return (column == index + 1); } }); fireTableColumnChanged(index + 1); //System.out.println(PropertiesTableModel.this.toString()); break; // one item changed case PropertyBundleEvent.CHANGE_ITEM: final int index2 = obj.getBundleStructure().getEntryIndexByFileName(evt.getEntryName()); final int keyIndex = obj.getBundleStructure().getKeyIndexByName(evt.getItemName()); if (index2 == -1 || keyIndex == -1) { if (Boolean.getBoolean("netbeans.debug.exceptions")) (new Exception("Changed file not found")).printStackTrace(); break; } cancelEditingInTables(new CancelSelector() { public boolean doCancelEditing(int row, int column) { if (!(row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount())) return false; return (column == index2 + 1 && row == keyIndex); } }); fireTableCellUpdated(keyIndex, index2 + 1); //System.out.println(PropertiesTableModel.this.toString()); break; } } } // endof inner class TablePropertyBundleListener /** Returns the class for a model. */ public Class getColumnClass(int columnIndex) { return StringPair.class; } /** Returns the number of rows in the model */ public int getRowCount() { return obj.getBundleStructure().getKeyCount(); } /** Returns the number of columns in the model */ public int getColumnCount() { return obj.getBundleStructure().getEntryCount() + 1; } /** Returns the value for the given row and column */ public Object getValueAt(int row, int column) { BundleStructure bs = obj.getBundleStructure(); switch (column) { case 0: return stringPairForKey(row);//bs.getNthKey(row); default: Element.ItemElem item = bs.getItem(column - 1, row); return stringPairForValue(item); /* if (item == null) return ""; else return item.getValue(); */ } } /* Returns a string pair for a key in an item (may be null). */ private StringPair stringPairForKey(int row) { BundleStructure bs = obj.getBundleStructure(); Element.ItemElem item = bs.getItem(0, row); StringPair sp; if (item == null) sp = new StringPair("", bs.getNthKey(row), true); else sp = new StringPair(item.getComment(), bs.getNthKey(row), true); if (obj.getBundleStructure().getEntryCount() > 1) sp.setCommentEditable(false); return sp; } /* Returns a string pair for a value in an item (may be null). */ private StringPair stringPairForValue(Element.ItemElem item) { if (item == null) return new StringPair(); else return new StringPair(item.getComment(), item.getValue()); } /** Returns the name for a column */ public String getColumnName(int column) { switch (column) { case 0: return NbBundle.getBundle(PropertiesTableModel.class).getString("LAB_KeyColumnLabel"); default: if (obj.getBundleStructure().getEntryCount() == 1) return NbBundle.getBundle(PropertiesTableModel.class).getString("LBL_ColumnValue"); else return Util.getPropertiesLabel (obj.getBundleStructure().getNthEntry(column - 1)); } } /** Sets the value at rowIndex and columnIndex */ public void setValueAt(Object aValue, int rowIndex, int columnIndex) { // PENDING - set comment for all files if (columnIndex == 0) { BundleStructure bs = obj.getBundleStructure(); String oldValue = (String)bs.getNthKey(rowIndex); if (oldValue == null) return; String newValue = ((StringPair)aValue).getValue(); if ((newValue == null) || (newValue.length() == 0)) { // remove from all files return; /*for (int i=0; i < obj.getBundleStructure().getEntryCount(); i++) { PropertiesFileEntry entry = obj.getBundleStructure().getNthEntry(i); if (entry != null) { PropertiesStructure ps = entry.getHandler().getStructure(); if (ps != null) { ps.deleteItem(oldValue); } } }*/ } else { // set in all files for (int i=0; i < obj.getBundleStructure().getEntryCount(); i++) { PropertiesFileEntry entry = obj.getBundleStructure().getNthEntry(i); if (entry != null) { PropertiesStructure ps = entry.getHandler().getStructure(); if (ps != null) { // set the key if (!oldValue.equals(newValue)) { ps.renameItem(oldValue, newValue); } // set the comment if (i == 0) { Element.ItemElem item = ps.getItem(newValue); if (item != null && ((StringPair)aValue).isCommentEditable()) { // only set if they differ if (!item.getComment().equals(((StringPair)aValue).getComment())) item.setComment(((StringPair)aValue).getComment()); } } } } } } } else { // property value PropertiesFileEntry entry = obj.getBundleStructure().getNthEntry(columnIndex - 1); String key = obj.getBundleStructure().getNthKey(rowIndex); if (entry != null && key != null) { PropertiesStructure ps = entry.getHandler().getStructure(); if (ps != null) { Element.ItemElem item = ps.getItem(key); if (item != null) { item.setValue(((StringPair)aValue).getValue()); item.setComment(((StringPair)aValue).getComment()); } else { if ((((StringPair)aValue).getValue().length() > 0) || (((StringPair)aValue).getComment().length() > 0)) ps.addItem(key, ((StringPair)aValue).getValue(), ((StringPair)aValue).getComment()); } } } } } /** Returns true for all cells */ public boolean isCellEditable(int rowIndex, int columnIndex) { return true; } /** Fires a TableModelEvent - change of one column */ public void fireTableColumnChanged(int column) { fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1, column)); } public String toString() { StringBuffer result = new StringBuffer(); result.append("------------------------------ TABLE MODEL DUMP -----------------------\n"); for (int row = 0; row < getRowCount(); row ++) { for (int column = 0; column < getColumnCount(); column ++) { StringPair sp = (StringPair)getValueAt(row, column); result.append("[" /*+ sp.getComment() + "," */+ sp.getValue() + "]"); if (column == 0) result.append(" : "); else if (column == getColumnCount() - 1) result.append("\n"); else result.append(","); } } result.append("---------------------------- END TABLE MODEL DUMP ---------------------\n"); return result.toString(); } /** Cancels editing in all listening JTables if appropriate */ private void cancelEditingInTables(CancelSelector can) { Object list[] = listenerList.getListenerList(); for (int i = 0; i < list.length; i++) { if (list[i] instanceof JTable) { JTable jt = (JTable)list[i]; if (can.doCancelEditing(jt.getEditingRow(), jt.getEditingColumn())) { TableCellEditor ed = jt.getCellEditor(); if (ed != null) { ed.cancelCellEditing(); //System.out.println("canceling edit in " + jt); } } } } } /** Interface which finds out whether editing should be canceled if given cell is edited. */ private static interface CancelSelector { /** Returns whether editing should be canceled for given row and column. */ public boolean doCancelEditing(int row, int column); } private CancelSelector getDefaultCancelSelector() { return new CancelSelector() { /** Returns whether editing should be canceled for given row and column. */ public boolean doCancelEditing(int row, int column) { return (row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount()); } }; } /** Object for the value for one cell. * Encapsulates up to two values. * It is used to represent either (comment, value) pair of an item, or a key for an item. */ static class StringPair implements Serializable { private String comment; private String value; private boolean keyType; private boolean commentEditable; static final long serialVersionUID =-463968846283787181L; /** Constructs with empty comment and value. */ public StringPair() { this (null, "", false); } /** Constructs with the given value and no comment. */ public StringPair(String v) { this (null, v, true); } /** Constructs with the given comment and value. */ public StringPair(String c, String v) { this (c, v, false); } /** Constructs with the given comment and value. */ public StringPair(String c, String v, boolean kt) { comment = c; value = v; keyType = kt; commentEditable = true; } /** Returns the comment associated with this element. */ public String getComment() { return comment; } /** Returns the value associated with this element. */ public String getValue() { return value; } public Object clone() { String c = (comment == null ? null : new String(comment)); String v = (value == null ? null : new String(value)); return new StringPair(c, v); } public String toString() { return value; } /** Returns the type key/value of the pair. */ public boolean isKeyType () { return keyType; } /** Returns whether the comment should be allowed to be edited. */ public boolean isCommentEditable() { return commentEditable; } /** Sets whether the comment should be allowed to be edited. */ public void setCommentEditable(boolean newEditable) { commentEditable = newEditable; } } // end of inner class } /* * <<Log>> */